{\rtf0\ansi{\fonttbl\f4\fmodern Courier;\f9\ftech Symbol;\f2\fmodern Ohlfs;}
\margl40
\margr40
{\colortbl;\red0\green0\blue0;}
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f4\b0\i0\ulnone\fs24\fc0\cf0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//
\i 	
\b FILENAME
\b0 :	
\b\i0 eTAppUI.m\

\b0 //
\i 	
\b SUMMARY
\b0 :	
\b\i0 Implementation of eTAppUI, which works with eTApp and Appkit
\b0 \
//	
\b\i SUPERCLASS
\b0 :
\i0 	
\b Object:eTAppUI
\b0 \
//	
\b\i PROTOCOLS
\b0 :
\i0 	
\b None
\b0 \
//	
\b\i INTERFACE
\b0 :
\i0 	
\b eText.nib
\b0 \
//	
\b\i AUTHOR
\b0 :		
\b\i0 Rohit Khare
\b0 \
//	
\b\i COPYRIGHT
\b0 :	
\f9\i0 с
\f4\b 1993,94 California Institure of Technology, eText Project\

\b0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b\i Implementation Comments
\b0\i0 \
//		The nib has a lot of the intelligence hidden in its connections\
//	The main challenge is managing the UI, which is constantly changing. \
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b\i HISTORY\

\b0\i0 //	02/04/94:	
\b Added remote printing support.
\b0 \
//	11/20/94:	
\b Added History Panel UI.
\b0 \
//	10/29/94:	
\b Added Line Range hooks for modified MiscFindPanel.
\b0 \
//	10/22/94:	
\b Added Find Panel UI; from MiscFindPanelClass.
\b0 \
//	09/21/94:	
\b Revamped for eText5; removed savePanel, clean interface to eTApp
\b0 \
//	07/06/94:	
\b Added mailDevelopers:
\b0 \
//	05/21/94:	
\b Added savePanel code for multiple-format input.
\b0 \
//	05/05/94:	
\b Added "Accessory" support for future expansion
\b0 \
//	08/22/93:	
\b Added Tools UI
\b0 .\
//	08/16/93:	
\b Created. Implicitly supports an <eTextServices> protocol
\b0 \
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Imported Interfaces
\b0 \
//\
	#import "
\b eTAppUI.h
\b0 "\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Hacked NXApp mainWindow accessor
\b0 \
//\

\i @implementation Application (realMainWindow)\

\i0 // 
\i the mainWindow method returns nil when the app is not focused.
\i0 \
- 
\b realMainWindow
\b0  \{return 
\b mainWindow
\b0 ;\}\

\i @end\

\i0 \

\i @implementation eTAppUI\

\i0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b AppKit Delegate
\b0 \
//\
- 
\b appWillInit
\b0 :sender \{\
	
\b static BOOL hasInitted
\b0  = NO;\

\b 	if (hasInitted) return self;\
	\

\b0 	
\b infoController
\b0  = 
\b nil
\b0 ;\
	
\b annotationTable
\b0  = [[HashTable alloc] 
\b initKeyDesc
\b0 :"%"];\
	
\b agentTable
\b0  = [[HashTable alloc] 
\b initKeyDesc
\b0 :"%"];\
	
\b initMenu(
\b0 [NXApp mainMenu]);\
	[
\b FontManager
\b0  
\b setFontPanelFactory
\b0 :
\fc1\cf1 objc_lookUpClass("
\b DPFontPanel
\b0 ")
\fc0\cf0 ];\
	[NXApp 
\b setAutoupdate:YES
\b0 ];\
	[[
\b eTApp
\b0  alloc] 
\b init
\b0 ];\
	[self 
\b showInspector
\b0 :self];\
	[self 
\b showNavigator
\b0 :self];\
	//
\i  [self 
\b showHistory
\b0 :self];
\i0 \
	
\b hasInitted = YES
\b0 ;\
	return self;\
\}\
\
- 
\b appWillTerminate
\b0 :sender \{\
	return [
\b etApp shutdown:YES
\b0 ];\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b InfoController UI
\b0 \
//\
- 
\b showInfo
\b0 :sender \{\
	if (!infoController) 
\b infoController
\b0  = [[
\b InfoController
\b0  alloc] 
\b init
\b0 ];\
	[
\b infoController
\b0  
\b showInfo
\b0 ];\
	return self;\
\}\
\
- 
\b showCopyright
\b0 :sender \{\
	if (!infoController) 
\b infoController
\b0  = [[
\b InfoController
\b0  alloc] 
\b init
\b0 ];\
	[
\b infoController showCopyright
\b0 ];\
	return self;\
\}\
\
- 
\b mailDevelopers
\b0 :sender \{\
    char 
\b subject[512]
\b0 , 
\b body[512]
\b0 ;\
    id ret = self;\
\
    sprintf (
\b subject
\b0 , "
\b Comments, bugs, etc for 
\b0 %s
\b  version 
\b0 %s", \
             [NXApp 
\b appName
\b0 ], [NXApp 
\b versionStr
\b0 ]);\
    sprintf (
\b body
\b0 , "
\b This is truly the spiffiest app ever written."\
					" But, did you know...
\b0 \\n\\n\\n%s\\n",
\b NXUserName
\b0 ());\
    ret = [NXApp 
\b sendMailTo
\b0 :"
\b khare@w3.org
\b0 " cc:NULL \
				  
\b subject
\b0 :subject 
\b body
\b0 :body deliver:NO];\
    if (ret == nil)\
        
\b NXRunAlertPanel
\b0 ([NXApp appName],\
						"
\b Unable to contact Mail.app
\b0 ","OK",NULL,NULL);\
    return ret;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b UserModel UI
\b0 \
//\
- 
\b showPreferences
\b0 :sender \{\
	[
\b userModel showPreferences
\b0 ];\
	return self;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Navigator UI
\b0 \
//\
- 
\b showNavigator
\b0 :sender\{\
	[
\b navigator showNavigator
\b0 ];\
	return self;\
\}\
\
- 
\b showHistory
\b0 :sender\{\
	[
\b navigator showHistory
\b0 ];\
	return self;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Inspector UI
\b0 \
//\
- 
\b showInspector
\b0 :sender \{\
	[
\b inspector showInspector
\b0 ];\
	[[[[NXApp 
\b mainWindow
\b0 ] delegate] 
\b etDoc
\b0 ] 
\b inspect
\b0 ];\
	return self;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Tool Management/Registration UI
\b0 \
//\
- 
\b loadTool
\b0 :sender \{\
	const char *directory;\
	const char *const *files;\
	const char *toolType[6]=\{
\b BNDL_EXT
\b0 , 
\b TOOL_EXT
\b0 , 
\b ANNT_EXT
\b0 ,\
							  
\b AGNT_EXT
\b0 , 
\b ACCS_EXT
\b0 , NULL\};\
	int			i;\
	char 		path[MAXPATHLEN];\
		\
	
\b id openpanel
\b0  = [[
\b OpenPanel
\b0  
\b new
\b0 ] 
\b allowMultipleFiles:YES
\b0 ];\
	[openpanel 
\b setTreatsFilePackagesAsDirectories:NO
\b0 ];\
	[openpanel 
\b chooseDirectories:NO
\b0 ];\
	i = [openpanel runModalForTypes:toolType];\
	if (!i) return self;\
	files = [openpanel filenames];\
	directory = [openpanel directory];\
	i = 0;\
	while (files && files[i])\{\
		strcpy(path, directory);\
		strcat(path, "/");\
		strcat(path, files[i]);\
		[
\b self
\b0  
\b openFromPath
\b0 :NXUniqueString(
\b path
\b0 )\
			  
\b type
\b0 :NXUniqueString(
\b rindex
\b0 (
\b path
\b0 ,'
\b .
\b0 ')+1)];\
		i++;\
	\}\
    return self;\
\}\
\
- 
\b registerAnnotation
\b0 :(NXAtom) 
\b menuLabel\

\b0 				 
\b key
\b0 :(char) 
\b key
\b0 \
				
\b name
\b0 :(NXAtom) 
\b name
\b0 \
				
\b icon
\b0 :(NXImage *) 
\b icon
\b0  \{\
	
\b static id	_submenuTable
\b0 =nil;\
\
	if ([annotationTable 
\b isKey
\b0 :
\b menuLabel
\b0 ]) 
\b return
\b0  
\b self
\b0 ;\
	if (
\b !_submenuTable
\b0 )\

\b 		_submenuTable
\b0  = [[HashTable alloc] 
\b initKeyDesc
\b0 :"%"];\
\
	if (
\b index
\b0 (menuLabel, '
\b /
\b0 ') && (*menuLabel != '/')) \{ // 
\i is there a slash?\

\i0 		char tmp[256]; // C Programmer's Disease\
		id	_submenu;\
		NXAtom	tmpA;\
		\
		
\b strncpy
\b0 (
\b tmp
\b0 , 
\b menuLabel
\b0 , 256);\
		if (index(tmp, '/')) 
\b *index(tmp, '/') = 0
\b0 ; //
\i  cut out the prefix
\i0 \
		
\b tmpA
\b0  = 
\b NXUniqueString
\b0 (
\b tmp
\b0 );\
		_submenu = [
\b _submenuTable
\b0  
\b valueForKey
\b0 :
\b tmpA
\b0 ];\
		if (
\b !_submenu
\b0 ) \{\
			
\b _submenu
\b0  = [[Menu alloc] 
\b initTitle
\b0 :
\b tmpA
\b0 ];\
			[annotationMenu
\b  setSubmenu
\b0 :
\b _submenu
\b0  
\b forItem
\b0 :\
				[annotationMenu 
\b addItem
\b0 :
\b tmpA
\b0  \
								 
\b action
\b0 :@selector(
\b submenuAction
\b0 :)\
								 keyEquivalent:'\\0']];\
			[
\b _submenuTable
\b0  
\b insertKey
\b0 :tmpA 
\b value
\b0 :_submenu];\
		\}\
		[[
\b _submenu addItem
\b0 : (
\b index
\b0 (menuLabel,'
\b /
\b0 ')+1)\
					
\b action
\b0 : @selector(
\b annotationAction
\b0 :)\
			
\b keyEquivalent
\b0 : 
\b key
\b0 ]\
			
\b setUpdateAction
\b0 :@selector(
\b menuItemUpdate
\b0 :) 
\b forMenu
\b0 :
\b _submenu
\b0 ];\
		[
\b annotationTable
\b0  
\b insertKey
\b0 :(
\b index
\b0 (menuLabel,'
\b /
\b0 ')+1) 
\b value
\b0 :(STR)
\b name
\b0 ];\
	\} else \{\
		[[
\b annotationMenu
\b0  
\b addItem
\b0 : 
\b menuLabel\

\b0 						  
\b action
\b0 : @selector(
\b annotationAction
\b0 :)\
				  
\b keyEquivalent
\b0 : 
\b key
\b0 ]\
		
\b setUpdateAction
\b0 :@selector(
\b menuItemUpdate
\b0 :) 
\b forMenu
\b0 :
\b annotationMenu
\b0 ];\
		[
\b annotationTable
\b0  
\b insertKey
\b0 :
\b menuLabel
\b0  
\b value
\b0 :(STR)
\b name
\b0 ];\
	\}\
	if (
\b icon
\b0 ) \{\
		// 
\i Eventually...  [ToolsPalette addTool:icon]
\i0 \
	\}\
	return self;\
\}\
\
- 
\b registerAgent
\b0 :(NXAtom) 
\b menuLabel\

\b0 			
\b key
\b0 :(char) 
\b key
\b0 \
			
\b name
\b0 :(NXAtom) 
\b name
\b0  \{	\
	if (
\b !
\b0 [agentTable 
\b isKey
\b0 :menuLabel]) \{\
		[agentTable 
\b insertKey
\b0 :
\b menuLabel
\b0  value:(STR)name];\
		[
\b agentMenu
\b0  
\b addItem
\b0 : 
\b menuLabel
\b0 \
					
\b action
\b0 : @selector(
\b agentAction
\b0 :)\
			 
\b keyEquivalent
\b0 : 
\b key
\b0 ];\
	\}\
	return self;\
\}\
\
- 
\b registerAccessory
\b0 :(NXAtom) 
\b menuLabel\

\b0 				 
\b key
\b0 :(char) 
\b key
\b0 \
				
\b name
\b0 :(NXAtom) 
\b name
\b0 \
			  
\b target
\b0 :(id) 
\b theTarget
\b0 \
			  
\b action
\b0 :(SEL) 
\b theAction
\b0 ;\
\{	\
	[[
\b accessoryMenu
\b0  
\b addItem
\b0 : 
\b menuLabel\

\b0 					  
\b action
\b0 : 
\b theAction
\b0 \
			  
\b keyEquivalent
\b0 : 
\b key
\b0 ] 
\b setTarget
\b0 :
\b theTarget
\b0 ];\
	return self;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Document Management UI
\b0 \
//\
- 
\b new
\b0 :sender \{\
	[
\b etApp createID
\b0 ];	//
\i returns new docID
\i0 \
    return self;\
\}\
\
- 
\b open
\b0 :sender \{\
	const char *directory, *docdir;\
	const char *const *files;\
	const char *
\b etfdType
\b0 [5] = \{
\b ETFD_EXT
\b0 , 
\b RTFD_EXT
\b0 , 
\b RTF_EXT
\b0 , 
\b LINK_EXT
\b0 , NULL\};\
	int			i;\
	char 		path[MAXPATHLEN];\
	static BOOL firstTime=YES;\
		\
	id 
\b openpanel
\b0  = [[OpenPanel 
\b new
\b0 ] 
\b allowMultipleFiles
\b0 :
\b YES
\b0 ];\
	[openpanel 
\b setTreatsFilePackagesAsDirectories:NO
\b0 ];\
	[openpanel 
\b chooseDirectories:NO
\b0 ];\
	\
	if (firstTime) \{\
		
\b docdir
\b0  = [userModel 
\b stringQuery
\b0 :
\b ETFDIRECTORY
\b0 ];\
		if (docdir && *docdir) \{\
			[openpanel 
\b setDirectory
\b0 :
\b docdir
\b0 ];\
		\}\
		firstTime = NO;\
	\}\
	i = [openpanel runModalForTypes:etfdType];\
	if (!i) return self;\
	files = [openpanel filenames];\
	directory = [openpanel directory];\
	i = 0;\
	while (files && files[i])\{\
		strcpy(path, directory);\
		strcat(path, "/");\
		strcat(path, files[i]);\
		[
\b self
\b0  
\b openFromPath
\b0 :NXUniqueString(
\b path
\b0 )\
			  
\b type
\b0 :
\b rindex
\b0 (
\b path
\b0 ,'
\b .
\b0 ') ? NXUniqueString(
\b rindex
\b0 (
\b path
\b0 ,'
\b .
\b0 ')+1) : ""];\
		i++;\
	\}\
    return self;\
\}\
\
- 
\b openAsText
\b0 :sender \{\
	const char *directory;\
	const char *const *files;\
	const char *
\b textType
\b0 [1] = \{NULL\};\
	int			i;\
	char 		path[MAXPATHLEN];\
		\
	id 
\b openpanel
\b0  = [[OpenPanel 
\b new
\b0 ] 
\b allowMultipleFiles
\b0 :
\b YES
\b0 ];\
	[openpanel 
\b setTreatsFilePackagesAsDirectories:YES
\b0 ];\
	[openpanel 
\b chooseDirectories:NO
\b0 ];\
	i = [openpanel runModalForTypes:textType];\
	if (!i) return self;\
	files = [openpanel filenames];\
	directory = [openpanel directory];\
	i = 0;\
	while (files && files[i])\{\
		strcpy(path, directory);\
		strcat(path, "/");\
		strcat(path, files[i]);\
		[
\b self
\b0  
\b openFromPath
\b0 :NXUniqueString(
\b path
\b0 )\
			  
\b type
\b0 :NXUniqueString("")];\
		i++;\
	\}\
    return self;\
\}\
\
- 
\b openFromPath
\b0 :(const char *)
\b path
\b0  
\b type
\b0 :(const char *)
\b aType
\b0  \{ \
	id 
\b theDocInfo
\b0 ;\
	\
	if(!strcmp(aType, 
\b ETFD_EXT
\b0 )) \{\
		[
\b etApp
\b0  
\b openID
\b0 :[[[[
\b eTDocInfo
\b0  alloc] 
\b init
\b0 ]\
						
\b readComponentFromPath
\b0 :NXUniqueString(
\b path
\b0 )] \
						
\b docID
\b0 ]];\
\
	\} else if(!strcmp(aType, 
\b LINK_EXT
\b0 )) \{\
		char tmp[64];\
		long dID,aID;\
		id 
\b theTable
\b0  = [[[
\b NXStringTable
\b0  alloc] init] 
\b readFromFile
\b0 :
\b path
\b0 ];\
		\
		strncpy(tmp, [theTable 
\b valueForStringKey
\b0 :
\b DOCID
\b0 ],63);\
		
\b sscanf
\b0 (tmp, "%x",&
\b dID
\b0 );\
		[
\b etApp
\b0  
\b openID
\b0 :
\b dID
\b0 ];\

\b\i \

\b0\i0 		strncpy(tmp, [theTable 
\b valueForStringKey
\b0 :
\b ANCHORID
\b0 ],63);\
		theTable = [[theTable 
\b empty
\b0 ] 
\b free
\b0 ];\
		
\b sscanf
\b0 (tmp, "%x",&
\b aID
\b0 );
\b\i \
		// This is a really severe kernel violation!\
		[[[objc_lookUpClass("eTBookmarkBinder") new] \
				bookmarkForID:aID] highlight:self];\
				\

\b0\i0 	\} else if((!strcmp(aType,
\b HTMD_EXT
\b0 )) || (!strcmp(aType,
\b OLD_HTMD_EXT
\b0 ))) \{\
		char bounce[MAXPATHLEN];\
		\
		
\b sprintf
\b0 (
\b bounce
\b0 ,"%s
\b /"HTML_INDEX
\b0 ,
\b path
\b0 );\
		[[Application 
\b workspace
\b0 ] 
\b openFile
\b0 :
\b bounce
\b0 ];\
\
	\} else if(!strcmp(aType, 
\b URI_EXT
\b0 )) \{\
		NXStream *s;\
		char *data, *url;\
		Pasteboard *thePB;\
		int len, maxlen;\
		\
		s = NXMapFile(path, NX_READONLY);\
		NXGetMemoryBuffer(s, &data, &len, &maxlen);\
		if (!strncmp(data, "
\b URL:
\b0 ",4)) url = data+4;\
			else if (!strncmp(data, "
\b <URL:
\b0 ",5)) url = data+5;\
			else url = data;\
		\
		thePB = [Pasteboard newUnique];\
		[thePB declareTypes:&NXAsciiPboardType num:1 owner:nil];\
		[thePB writeType:NXAsciiPboardType data:(url) length:strlen(url)];\
\

\i\fs28 		if (!NXPerformService("
\b Open URL
\b0 ", thePB) &&\
			 !NXPerformService("
\b OmniWeb/Open URL
\b0 ", thePB) &&\
			 !NXPerformService("
\b SpiderWoman/Open URL
\b0 ", thePB))\

\i0\fs24 			NXRunAlertPanel("eTApp","Could not open a "
\b URI_EXT
\b0 " file (using services): %s.", "OK", NULL, NULL, url);\
		\
		NXCloseMemory(s, NX_FREEBUFFER);\
		\
	\} else if(!strcmp(aType, 
\b TeXD_EXT
\b0 )) \{\

\fc1\cf1 		[
\b navigator
\b0  
\b find
\b0 :"\\\\.
\b tex$
\b0 " 
\b inDir
\b0 :(STR)
\b\fc0\cf0 path\

\b0\fc1\cf1 					target:
\fc0\cf0 [Application 
\b workspace
\b0 ]
\fc1\cf1  action:@selector(
\b\fc0\cf0 openFile
\b0\fc1\cf1 :)];\

\fc0\cf0 \
	\} else if ((!strcmp(aType, 
\b DOCI_EXT
\b0 )) || (!strcmp(aType, 
\b NAVI_EXT
\b0 ))) \{\

\fc1\cf1 		// 
\i Create an eTDocInfo, without opening the document\
		
\i0 [etApp 
\b loadDocInfoFromPath
\b0 :path];\
		// 
\i Navigator will redisplay on the next autoupdate
\i0 \

\fc0\cf0 \
	\} else if((!strcmp(aType, 
\b AGNT_EXT
\b0 )) || (!strcmp(aType, 
\b TOOL_EXT
\b0 )) ||\
			  (!strcmp(aType, 
\b BNDL_EXT
\b0 )) || (!strcmp(aType, 
\b ANNT_EXT
\b0 )) ||\
			  (!strcmp(aType, 
\b DSBD_EXT
\b0 )) || (!strcmp(aType, 
\b ACCS_EXT
\b0 ))) \{\
		[
\b etApp
\b0  
\b loadToolFromPath
\b0 :
\b path
\b0 ];\
		\
	\} else \{ // 
\i Pass along a virgin docInfo with the path (RTFD, RTF, or text)
\i0 .\
		char tmp[MAXPATHLEN], *ext;\
\
		
\b theDocInfo
\b0  = [[
\b eTDocInfo
\b0  alloc] 
\b init
\b0 ];\
		// 
\i set the doc's title to be the old name (foo)
\i0 \
		strcpy(tmp, 
\b rindex
\b0 (
\b path
\b0 ,'
\b /
\b0 ')+1);\
		ext = rindex(tmp,'.');\
		if (ext && ext+1 && !strcmp(ext+1, 
\b RTFD_EXT
\b0 ) && !strcmp(ext+1, 
\b RTF_EXT
\b0 ))\
			*
\b ext
\b0  = 
\b 0
\b0 ;\
		[theDocInfo 
\b setDocTitle
\b0 :tmp];\
		[theDocInfo 
\b setDocPath
\b0 :
\b path
\b0 ];\
		[
\b etApp
\b0  
\b openID
\b0 :[
\b theDocInfo
\b0  
\b docID
\b0 ]];\
\
		// 
\i now that everything is hunky-dory, set a NEW pathname and touch it
\i0 \
		// 
\i set the path to be /directory/foo/was/in/foo.id.etfd
\i0 \
		strcpy(tmp, 
\b path
\b0 );\
		ext = rindex(tmp,'.');\
		if (ext && ext+1 && !strcmp(ext+1, 
\b RTFD_EXT
\b0 ) && !strcmp(ext+1, 
\b RTF_EXT
\b0 ))\
			*
\b ext
\b0  = 
\b 0
\b0 ;\
		
\b strcat
\b0 (tmp, "."
\b ETFD_EXT
\b0 );\
		
\b while
\b0  (!
\b access
\b0 (tmp,
\b F_OK
\b0 )) \{	// 
\i hey, the odds are 1 in 2^32, but...\

\i0 			
\b sprintf
\b0 (
\b rindex
\b0 (
\b tmp
\b0 ,'
\b .
\b0 '),"
\b .%x.
\b0 "
\b ETFD_EXT
\b0 ,[NXApp 
\b uniqueID
\b0 ]);\
		\}\
		[theDocInfo 
\b setDocPath
\b0 :
\b tmp
\b0 ];\
		[[theDocInfo 
\b etDoc
\b0 ] 
\b touch
\b0 ];\
	\}\
	return self;\
\}\
\
- 
\b import
\b0 :sender \{\
	const char *directory;\
	const char *const *files;\
	NXAtom	   *importTypes;\
	int			i;\
	char 		path[MAXPATHLEN];\

\b 	static id	thePboard=nil;\

\b0 	id			openpanel;\
	NXAtom		filterHack;\
\
	// 
\b\i Transparency violation
\b0\i0 \
	if (
\b !
\b0 [[[[NXApp 
\b mainWindow
\b0 ] 
\b delegate
\b0 ] 
\b etDoc
\b0 ] 
\b acceptsAnnotation
\b0 ])\{\
		NXBeep(); return nil;\
	\}\
	\
	
\b openpanel
\b0  = [[OpenPanel new] 
\b allowMultipleFiles
\b0 :
\b YES
\b0 ];\
	[openpanel 
\b setTreatsFilePackagesAsDirectories
\b0 :
\b NO
\b0 ]; // tough call!\
	[openpanel 
\b chooseDirectories
\b0 :
\b NO
\b0 ];\
\
	// 
\i see save panel docs. Assumes there is always an ANY_TYPE handler
\i0 \
	
\b filterHack
\b0  = NULL;\
	
\b importTypes
\b0  = 
\b &filterHack
\b0 ;\
\
	i = [openpanel runModalForTypes:importTypes];\
	if (!i) return self;\
	files = [openpanel filenames];\
	directory = [openpanel directory];\
	i = 0;\
	if (!
\b thePboard
\b0 ) 
\b thePboard
\b0  = [
\b Pasteboard newUnique
\b0 ];\
	while (files && files[i])\{\
		
\b id it
\b0 ;\
		\
		strcpy(path, directory);\
		strcat(path, "/");\
		strcat(path, files[i]);\
		\
		
\b importTypes
\b0 [0] = 
\b NXFileContentsPboardType
\b0 ;\
		[thePboard 
\b declareTypes
\b0 :
\b importTypes
\b0  num:1 owner:nil];\
		[thePboard 
\b writeFileContents
\b0 :
\b path
\b0 ];\
		
\b importTypes
\b0 [0] = 
\b NXFilenamePboardType
\b0 ;\
		[thePboard 
\b addTypes
\b0 :
\b importTypes
\b0  num:1 owner:nil];\
		[thePboard 
\b writeType
\b0 :importTypes[0] 
\b data
\b0 :
\b path
\b0  
\b length
\b0 :
\b strlen
\b0 (
\b path
\b0 )+
\b 1
\b0 ];\
		\
		
\b it
\b0  = [[
\b etApp
\b0  
\b annotationByPboard
\b0 :
\b thePboard
\b0 ] 
\b alloc
\b0 ];\
		if ([
\b it
\b0  
\b respondsTo
\b0 :@selector(
\b initFromPboard
\b0 :
\b inDoc
\b0 :
\b linked
\b0 :)]) \{\
			[
\b it
\b0  
\b initFromPboard
\b0 :
\b thePboard
\b0 \
			 
\b inDoc
\b0 :[[[NXApp 
\b mainWindow
\b0 ] 
\b delegate
\b0 ] 
\b etDoc
\b0 ]\
			 
\b linked
\b0 :
\b NO
\b0 ];\
			[[[[NXApp 
\b mainWindow
\b0 ] 
\b delegate
\b0 ] 
\b etDoc
\b0 ] 
\b insertAnnotation
\b0 :
\b it
\b0 ];\
		\} 
\b else
\b0  \{\
			it = [it 
\b free
\b0 ];\
			NXLogError("
\b Annotation did not respond to initFromPboard:::
\b0 ");\
			NXBeep();\
		\}\
		i++;\
	\}\
	// 
\i Attempt to free the imported data from VM.
\i0 \
	[
\b thePboard
\b0  
\b declareTypes
\b0 :importTypes 
\b num:0
\b0  
\b owner
\b0 :
\b nil
\b0 ];\
    return self;\
\}\
\
- 
\b saveAll
\b0 :sender \{\
	[
\b etApp
\b0  
\b saveAll
\b0 ];\
	return self;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Find Panel UI
\b0 \
//\
- 
\b enterSelection
\b0 :sender \{\
	return [[
\b MiscFindPanel
\b0  
\b sharedInstance
\b0 ] 
\b enterSelection
\b0 :sender];\}\
- 
\b findNext
\b0 :sender \{\
	return [[
\b MiscFindPanel
\b0  
\b sharedInstance
\b0 ] 
\b findForward
\b0 :sender];\}\
- 
\b findPrevious
\b0 :sender \{\
	return [[
\b MiscFindPanel
\b0  
\b sharedInstance
\b0 ] 
\b findBackward
\b0 :sender];\}\
- 
\b jumpToSelection
\b0 :sender \{\
	return [[
\b MiscFindPanel
\b0  
\b sharedInstance
\b0 ] 
\b jumpToSelection
\b0 :sender];\}\
- 
\b orderFrontFindPanel
\b0 :sender \{\
	return [[
\b MiscFindPanel
\b0  
\b sharedInstance
\b0 ] 
\b makeKeyAndOrderFront
\b0 :sender];\}\
- 
\b orderFrontRangePanel
\b0 :sender \{\
	return [[
\b MiscFindPanel
\b0  
\b sharedInstance
\b0 ] 
\b orderFrontRangePanel
\b0 :sender];\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Workspace Delegate
\b0 \
//\
- (BOOL)
\b appAcceptsAnotherFile
\b0 :sender\
\{\
	return 
\b YES
\b0 ;\
\}\
\
- (int)
\b app
\b0 :sender 
\b openFile
\b0 :(const char *)
\b path
\b0  
\b type
\b0 :(const char *)
\b aType
\b0 \
\{\
	[self 
\b appWillInit
\b0 :self];\
	[self 
\b openFromPath
\b0 :NXUniqueString(path) 
\b type
\b0 :aType];\
	return YES;\
\}\
\
- (int)
\b app
\b0 :sender 
\b openTempFile
\b0 :(const char *)path 
\b type
\b0 :(const char *)aType\
\{\
	[self 
\b app
\b0 :sender 
\b openFile
\b0 :path 
\b type
\b0 :aType];\
	
\b unlink
\b0 (
\b path
\b0 );\
    return YES;\
\}\
\
- 
\b app
\b0 :sender 
\b powerOffIn
\b0 :(int)ms 
\b andSave
\b0 :(int)aFlag\
\{\
	[
\b etApp
\b0  
\b shutdown
\b0 :
\b NO
\b0 ];\
	return self;\
\}\
\
// 
\i This is an example of poor programming style.\

\i0 static BOOL 
\b msgPrintRunPrintPanel
\b0 =YES;\
\
-(BOOL)
\b shouldRunPrintPanel
\b0 :aView \{return 
\b msgPrintRunPrintPanel
\b0 ;\} \
\
// 
\i The following is ripped off from Draw.app
\i0 .\

\fc1\cf1 - (int)
\b msgPrint
\b0 :(const char *)fullPath 
\b ok
\b0 :(int *)flag\
\{\
    id document = nil;\
	char aType[MAXPATHLEN];\
	\
	if (rindex(fullPath,'.') && *(rindex(fullPath,'.')+1))\
		strcpy(aType, rindex(fullPath,'.')+1);\
	else\
		*aType = '\\0';\
	
\fc0\cf0 [self 
\b app
\b0 :self 
\b openFile
\b0 :fullPath 
\b type
\b0 :aType];\
	//
\i The NXApp mainWindow method returns 0 if we're not the focused App.\
	
\i0 //
\i See the beginning of this file for the answer.\
	
\i0 //
\i I tried and tried, but ObjC refuses to compile a straight dereference
\i0\fc1\cf1 \
	if (document = [[
\b NXApp
\b0  
\b realMainWindow
\b0 ] delegate]) \{\
		
\b\fc0\cf0 msgPrintRunPrintPanel
\b0\fc1\cf1  = NO;\
		[document 
\b print
\b0 :self];\
		
\b\fc0\cf0 msgPrintRunPrintPanel
\b0\fc1\cf1  = YES;\
		*flag = YES;\
	\} else \{\
		*flag = NO;\
	\}\
    return 0;\
\}\
\
\

\fc0\cf0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Menu Delegate
\b0 \
//	
\i The following code is ripped off of Draw.app. This is perfectly legal
\i0 .\
//\
- (BOOL)
\b menuItemUpdate
\b0 :(MenuCell *)
\b menuCell
\b0 \
/*\

\i  * Method called by all menu items which send their actions to the\
 * First Responder.  First, if the object which would respond were the\
 * action sent down the responder chain also responds to the message\
 * validateCommand:, then it is sent validateCommand: to determine\
 * whether that command is valid now, otherwise, if there is a responder\
 * to the message, then it is assumed that the item is valid.\
 * The method returns YES if the cell has changed its appearance (so that\
 * the caller (a Menu) knows to redraw it).\

\i0  */\
\{\
    SEL action;\
    id responder, target;\
    BOOL enable;\
\
    
\b target
\b0  = [menuCell 
\b target
\b0 ];\
    
\b enable
\b0  = [menuCell 
\b isEnabled
\b0 ];\
    if (
\b !target
\b0 ) \{\
		
\b action
\b0  = [menuCell 
\b action
\b0 ];\
		
\b responder
\b0  = [NXApp 
\b calcTargetForAction
\b0 :
\b action
\b0 ];\
		if ([
\b responder
\b0  
\b respondsTo
\b0 :@selector(
\b validateCommand
\b0 :)]) \{\
			return([
\b responder
\b0  
\b validateCommand
\b0 :
\b menuCell
\b0 ]);\
		\} else \{\
			
\b enable
\b0  = 
\b responder
\b0  ? YES : NO;\
		\}\
    \}\
\
    if ([menuCell 
\b isEnabled
\b0 ] != 
\b enable
\b0 ) \{\
		[menuCell 
\b setEnabled
\b0 :
\b enable
\b0 ];\
		return 
\b YES
\b0 ;\
	\} else \{\
		return 
\b NO
\b0 ;\
	\}\
\}\
\
- (BOOL)
\b validateCommand
\b0 :(MenuCell *)
\b menuCell
\b0 \
\{\
    SEL 
\b action
\b0  = [menuCell 
\b action
\b0 ];\
	BOOL enable;\
\
    if (action == @selector(
\b saveAll:
\b0 )) \{\
		
\b enable
\b0  = [
\b etApp
\b0  
\b validateSaveAll
\b0 ];\
   		if ([menuCell isEnabled] != enable) \{\
			[menuCell setEnabled:enable];\
			return YES;\
		\} else \{\
			return NO;\
   		\}\
    \}\
    if ((action == @selector(
\b annotationAction:
\b0 )) ||\
		(action == @selector(
\b import:
\b0 )))\{\
		id foo = [[[NXApp 
\b mainWindow
\b0 ] 
\b delegate
\b0 ] 
\b etDoc
\b0 ];\
		
\b enable
\b0  = foo && [foo 
\b acceptsAnnotation
\b0 ];\
   		if ([menuCell isEnabled] != enable) \{\
			[menuCell setEnabled:enable];\
			return YES;\
		\} else \{\
			return NO;\
   		\}\
	\}\
    if (action == @selector(
\b agentAction:
\b0 )) \{\
		
\b enable
\b0  = [[[NXApp 
\b mainWindow
\b0 ] 
\b delegate
\b0 ] 
\b etDoc
\b0 ]? YES : NO;\
   		if ([menuCell isEnabled] != enable) \{\
			[menuCell setEnabled:enable];\
			return YES;\
		\} else \{\
			return NO;\
   		\}\
	\}\
    return NO;\
\}\
\
void 
\b initMenu
\b0 (Menu *
\b menu
\b0 )\
/*\

\i  * Sets the updateAction for every menu item which sends to the\
 * First Responder (i.e. their target is nil).  When autoupdate is on,\
 * every event will be followed by an update of each of the menu items\
 * which is visible.  This keep all unavailable menu items dimmed out\
 * so that the user knows what options are available at any given time.\
 * Returns the activate menu if is found in this menu.\

\i0  */ \
\{\
    int count;\
    Matrix *matrix;\
    MenuCell *cell;\
    id matrixTarget, cellTarget;\
\
    matrix = [menu itemList];\
	[menu setAutoupdate:YES];\
    matrixTarget = [matrix target];\
\
    count = [matrix cellCount];\
    while (count--) \{\
	cell = [matrix cellAt:count :0];\
	cellTarget = [cell target];\
	if (!matrixTarget && !cellTarget) \{\
	    [
\b cell
\b0  
\b setUpdateAction
\b0 :@selector(
\b menuItemUpdate
\b0 :) 
\b forMenu
\b0 :
\b menu
\b0 ];\
	\} else 
\b if
\b0  ([
\b cell
\b0  
\b hasSubmenu
\b0 ]) \{\
	    
\b initMenu
\b0 (
\b cellTarget
\b0 );\
	\}\
    \}\
\}\
\
- 
\b annotationAction
\b0 :sender\
\{	\
	if (
\b !
\b0 [[[NXApp 
\b mainWindow
\b0 ] 
\b delegate
\b0 ] 
\b etDoc
\b0 ])\
		return 
\b nil
\b0 ;\
	
\b if
\b0  ([[[[NXApp mainWindow] delegate] etDoc] 
\b acceptsAnnotation
\b0 ]) \{\
		
\b id it
\b0 ;\
		\
		
\b it
\b0  = [[
\b etApp
\b0  
\b annotationByName
\b0 :\
				[
\b annotationTable
\b0  
\b valueForKey
\b0 :\
					NXUniqueString([[
\b sender
\b0  
\b selectedCell
\b0 ] 
\b title
\b0 ])]\
				]\
			alloc];\
			\
		
\b if
\b0  ([
\b it
\b0  
\b respondsTo
\b0 :@selector(
\b initFromPboard
\b0 :
\b inDoc
\b0 :
\b linked
\b0 :)]) \{\
			[
\b it
\b0  
\b initFromPboard
\b0 :
\b nil
\b0 \
				
\b inDoc
\b0 :[[[NXApp 
\b mainWindow
\b0 ] 
\b delegate
\b0 ] 
\b etDoc
\b0 ]\
				linked:NO];\
			[[[[NXApp mainWindow] delegate] etDoc] 
\b insertAnnotation
\b0 :
\b it
\b0 ];\
		\} 
\b else
\b0  \{\
			it = [it 
\b free
\b0 ];\
			NXLogError("
\b Annotation did not respond to initFromPboard:::
\b0 ");\
			NXBeep();\
		\}\
	\}\
	return self;\
\}\
\
- 
\b agentAction
\b0 :sender\
\{	\
	if (
\b !
\b0 [[[NXApp 
\b mainWindow
\b0 ] 
\b delegate
\b0 ] 
\b etDoc
\b0 ])\
		return nil;\
	[[[[NXApp mainWindow] delegate] etDoc]\
		
\b attachAgent
\b0 :\
		[[[
\b etApp
\b0  
\b agentByName
\b0 :\
		[
\b agentTable
\b0  
\b valueForKey
\b0 :NXUniqueString([[
\b sender
\b0  
\b selectedCell
\b0 ] 
\b title
\b0 ])]]\
		alloc] 
\b init
\b0 :[[[[NXApp mainWindow] delegate] 
\b etDoc
\b0 ] 
\b docInfo
\b0 ]]];\
	return self;\
\}\
\
@end
}
